#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "logger.h"
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include <sys/time.h>

#define MAX_NUM 10000000

char file_log_name[] = "log.txt";
size_t fsize;
int array_length = 0;
int fd[3];
int array[MAX_NUM];


int *
get_array (char *string){

	int length = strlen(string);
	int i;
	char buff[20];
	strcpy(buff,"");
	int size = MAX_NUM;

	memset(array, 0, MAX_NUM);
	int j = 0;
	int num = 0;
	

	for (i = 0; i < length; ++i){
		

		int coma = 0;
		int	minus = 0;
		int numb = 0;
		
		if ( ((int)string[i] <= '9') && ((int)string[i] >= '0'))
			numb = 1;
		else
			if ((int)string[i] == ',')
				coma = 1;
			else
				if ((int)string[i] == '-')
					minus = 1;
		if ((( (!numb) && (!minus) && (j == 0)) || ((!numb) && (!coma) && (j > 0)) || (j >= 8)) || ((j >0) && ((int) buff[j-1] =='-') && (coma)))  {
			printf("Illegal input\n");
			exit(13);
		}

		if ((numb) || ((minus) && (j == 0)))  {
			strncat(buff,&string[i],1);
			j++;
			if (i != (length - 1))
				continue;
		}

		num = MAX_NUM/2 + atoi(buff);
		
		assert (num < MAX_NUM);
		array[num] += 1;
		j = 0;

		strcpy(buff,"");


	}


	return array;
}


int
open_file (char *file_name, int flag)
{

	int fd = open (file_name, flag,0666);
	if (fd < 0)
	  {
		  printf ("Bad file name. Try --help\n");
		  LOG_PRINT(ERROR,strerror (errno));
	  }
	return fd;
}

size_t
get_file_size (int fd)
{
	
	LOG_PRINT (INFO,"Started");
	struct stat buf;

	if (fstat (fd, &buf) < 0)
		LOG_PRINT(ERROR,strerror (errno));

	fsize = buf.st_size;
	return fsize;
}

char *
map_file (int fd, size_t fsize, int flag)
{

	char *ptr = (char *) mmap (NULL, fsize, flag, MAP_PRIVATE, fd, 0);

	if ((void *) ptr == MAP_FAILED)
		LOG_PRINT(ERROR,strerror (errno));

	return ptr;

}

void
print_array (int *array)
{
	
	LOG_PRINT (INFO,"Started");
	int i = 0;
	for (i = 0; i < array_length; ++i)
	  {
		  printf ("%d\n", array[i]);
	  }
	LOG_PRINT (INFO,"Finished");
}

void
write_to_file_2(char *output_name, int len){

	FILE * pFile;
	int i;
	pFile = fopen (output_name, "w" );

	for (i = 0; i < MAX_NUM; i++)
		{
			if (array[i] != 0){
				int j = 0;
				for (j = 0; j < array[i]; j++){
					fprintf( pFile, "%d,", i - MAX_NUM/2);
				}
			}
		}

	fclose (pFile);
}

void
print_help (char *string)
{

	if (strcmp (string, "-help") == 0)
	  {
		  printf ("First arg: csv-file's name\nSecond arg: outputfile \n[Third argument: logger level. 0 - show all info, 1 - except info, 2 - except warnings]\nReturns sorted array. Constructions with letter or other symbols will be replaced by zero.\nCheck log, if you want to know about working process\n");
		  exit (0);
	  }
	  printf("Enter -help for help\n");
}

void
print_str(char *argv){
 	int i;
 	for (i = 0; i < strlen(argv); ++i){
 		int d = (int)(argv[i]);
 		printf("%d ", d);
 	}
}

struct timeval tv1,tv2,dtv;
struct timezone tz;
void time_start() { 
	gettimeofday(&tv1, &tz); 
}

long time_stop(){ 
	gettimeofday(&tv2, &tz);
	dtv.tv_sec= tv2.tv_sec -tv1.tv_sec;
	dtv.tv_usec=tv2.tv_usec-tv1.tv_usec;
	if(dtv.tv_usec<0) { 
		dtv.tv_sec--; dtv.tv_usec+=1000000; 
	}

  return dtv.tv_sec*1000+dtv.tv_usec/1000;
}

int
main (int argc, char *argv[])
{


	assert (argc > 1);
	print_help (argv[1]);
	fd[3] = open_file(file_log_name, O_RDWR);
	log_start (fd[3]);
	assert (argc > 2);
	assert (strcmp(argv[1],file_log_name));
	assert (strcmp(argv[2],file_log_name));   
	fd[0] = open_file (argv[1], O_RDWR);
	assert ((int)get_file_size(fd[0])) ;

	fsize = get_file_size (fd[0]);
	char *addr = map_file (fd[0], fsize, PROT_WRITE | PROT_READ);
	time_start();
	get_array (addr);
	long int t = time_stop();
	printf("parse time:%ld\n",t);
	time_start();
	t = time_stop();
	printf("sort time:%ld\n",t);
	time_start();
	
	write_to_file_2(argv[2],array_length);
	

	t = time_stop();
	printf("munmap time:%ld\n",t);
	
	munmap (addr, fsize);
	close(fd[0]);
	close(fd[3]);
	return 0;
}
